﻿using System;
using System.Collections.Generic;

namespace YouVisio.Silverlight.TextDiff.Extensions
{
    public static class String_Ext
    {
        private static readonly char[] LINE_LIMITERS = new[] { '\n', '\r' };

        public static string Args(this string str, params object[] args)
        {
            return String.Format(str, args);
        }
        public static string FromToSubstring(this string str, int begin, int end)
        {
            return str.Substring(begin, end - begin);
        }
        public static T FoldEachLine<T>(this string source, T accumulator, Func<T, string, T> func, int startIndex = -1, int endIndex = -1)
        {
            if (source == null) return accumulator;
            if (startIndex < 0) startIndex = 0;
            if (endIndex < 0) endIndex = source.Length;
            int lineStart = startIndex;
            int lineEnd = -1;
            // Iterate the text, taking out a Substring for each line.
            // this is almost twise faster than text.split('\n') 
            while (lineEnd < endIndex)
            {
                lineEnd = source.IndexOfAny(LINE_LIMITERS, lineStart);
                var skip = lineEnd >= 0 && source.Length > (lineEnd + 1) &&
                           source[lineEnd] == '\r' &&
                           source[lineEnd + 1] == '\n'
                                ? 2
                                : 1;
                if (lineEnd == -1)
                {
                    lineEnd = endIndex;
                }

                var currentLine = source.FromToSubstring(lineStart, lineEnd);
                lineStart = lineEnd + skip;

                accumulator = func(accumulator, currentLine);
            }
            return accumulator;
        }
//public static Tuple<string, string, string> SameBeginningCompleteLines(this string one, string two)
//{
//    if (String.IsNullOrEmpty(one) || String.IsNullOrEmpty(two)) return new Tuple<string, string, string>("", one, two);
//    var lastBreakEndIndexA = -1;
//    var lastBreakEndIndexB = -1;
//    var skipA = 1;
//    for (int a = 0, b = 0; a < one.Length && b < two.Length; a++, b++)
//    {
//        var currA = one[a];
//        var currB = two[b];
//        var nextB = 0;
//        if (currA == '\r')
//        {
//            if (currB == '\r')
//            {
//                nextB = b + 1;
//                if (two.Length > nextB && two[nextB] == '\n')
//                {
//                    b++;
//                }
//                lastBreakEndIndexB = b + 1;
//            }
//            else if (currB == '\n')
//            {
//                lastBreakEndIndexB = b + 1;
//            }
//            else
//            {
//                break;
//            }
//            var nextA = a + 1;
//            if (one.Length > nextA && one[nextA] == '\n')
//            {
//                skipA = 2;
//                a++;
//            }
//            else skipA = 1;
//            lastBreakEndIndexA = a + 1;
//        }
//        else if (currA == '\n')
//        {
//            if (currB == '\r')
//            {
//                nextB = b + 1;
//                if (two.Length > nextB && two[nextB] == '\n')
//                {
//                    b++;
//                }
//                lastBreakEndIndexB = b + 1;
//            }
//            else if (currB == '\n')
//            {
//                lastBreakEndIndexB = b + 1;
//            }
//            else
//            {
//                break;
//            }
//            skipA = 1;
//            lastBreakEndIndexA = a + 1;
//        }
//        else if (currA != currB)
//        {
//            break;
//        }
//        var aIsLast = a == one.Length - 1;
//        var bIsLast = b == two.Length - 1;
//        if (aIsLast || bIsLast)
//        {
//            if (aIsLast && bIsLast) return new Tuple<string, string, string>(one, "", ""); // both end
//            var remaining = aIsLast ? two : one;
//            var remainingIndex = aIsLast ? b : a;
//            var nextChar = remaining[remainingIndex + 1];
//            var skip = 2;
//            if (nextChar == '\n' || nextChar == '\r')
//            {
//                if (nextChar == '\r' && (remaining.Length - 1) >= (remainingIndex + 2) && remaining[remainingIndex + 2] == '\n') skip = 3;
//                if (aIsLast) return new Tuple<string, string, string>(one, "", two.Substring(b + skip)); // only first ends
//                else /*if (bIsLast)*/ return new Tuple<string, string, string>(two, one.Substring(a + skip), ""); // only first ends
//            }
//            break;
//        }
//    }
//    if (lastBreakEndIndexA >= 0 && lastBreakEndIndexB >= 0)
//    {
//        return new Tuple<string, string, string>(
//                        one.Substring(0, lastBreakEndIndexA - skipA),
//                        one.Substring(lastBreakEndIndexA),
//                        two.Substring(lastBreakEndIndexB)
//                    );
//    }
//    return new Tuple<string, string, string>("", one, two);
//}
//public static Tuple<string, string, string> SameEndingCompleteLines(this string one, string two)
//{
//    if (String.IsNullOrEmpty(one) || String.IsNullOrEmpty(two)) return new Tuple<string, string, string>(one, two, "");
//    var lastBreakStartIndexA = -1;
//    var lastBreakStartIndexB = -1;
//    var skipA = 1;
//    for (int a = one.Length - 1, b = two.Length - 1; a >= 0 && b >= 0; a--, b--)
//    {
//        var currA = one[a];
//        var currB = two[b];
//        var nextB = 0;
//        if (currA == '\n')
//        {
//            if (currB == '\n')
//            {
//                nextB = b - 1;
//                if (nextB >= 0 && two[nextB] == '\r')
//                {
//                    b--;
//                }
//                lastBreakStartIndexB = b;
//            }
//            else if (currB == '\r')
//            {
//                lastBreakStartIndexB = b;
//            }
//            else
//            {
//                break;
//            }
//            var nextA = a - 1;
//            if (nextA >= 0 && one[nextA] == '\r')
//            {
//                skipA = 2;
//                a--;
//            }
//            else skipA = 1;
//            lastBreakStartIndexA = a;
//        }
//        else if (currA == '\r')
//        {
//            if (currB == '\n')
//            {
//                nextB = b - 1;
//                if (nextB >= 0 && two[nextB] == '\r')
//                {
//                    b--;
//                }
//                lastBreakStartIndexB = b;
//            }
//            else if (currB == '\r')
//            {
//                lastBreakStartIndexB = b;
//            }
//            else
//            {
//                break;
//            }
//            skipA = 1;
//            lastBreakStartIndexA = a;
//        }
//        else if (currA != currB)
//        {
//            break;
//        }
//        var aIsLast = a == 0;
//        var bIsLast = b == 0;
//        if (aIsLast || bIsLast)
//        {
//            if (aIsLast && bIsLast) return new Tuple<string, string, string>("", "", one); // both end
//            var remaining = aIsLast ? two : one;
//            var remainingIndex = aIsLast ? b : a;
//            var nextChar = remaining[remainingIndex - 1];
//            var skip = 2;
//            if (nextChar == '\n' || nextChar == '\r')
//            {
//                if (nextChar == '\n' && (remaining.Length - 1) >= (remainingIndex - 2) && remaining[remainingIndex - 2] == '\r') skip = 3;
//                if (aIsLast) return new Tuple<string, string, string>(one, "", two.Substring(b + skip)); // only first ends
//                else /*if (bIsLast)*/ return new Tuple<string, string, string>(two, one.Substring(a + skip), ""); // only first ends
//            }
//            break;
//        }
//    }
//    if (lastBreakStartIndexA >= 0 && lastBreakStartIndexB >= 0)
//    {
//        return new Tuple<string, string, string>(
//                        one.Substring(0, lastBreakStartIndexA),
//                        two.Substring(0, lastBreakStartIndexB),
//                        one.Substring(lastBreakStartIndexA + skipA)
//                    );
//    }
//    return new Tuple<string, string, string>(one, two, "");
//}
        public static string[] SplitLines(this string str)
        {
            if (str == null) return null;
            return str.FoldEachLine(
                            new List<string>(),
                            (l, s) =>
                            {
                                l.Add(s);
                                return l;
                            }
                            ).ToArray();
        }


    }
}
